package com.cmc6.menu.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cmc6.common.constant.BaseConstant;
import com.cmc6.common.exception.BaseBizCodeEnum;
import com.cmc6.common.mapper.MenuMapper;
import com.cmc6.common.model.dto.AddOrderNoDTO;
import com.cmc6.common.model.dto.NotEmptyIdSet;
import com.cmc6.common.model.dto.NotNullId;
import com.cmc6.common.model.entity.*;
import com.cmc6.common.util.ApiResult;
import com.cmc6.common.util.MyEntityUtil;
import com.cmc6.common.util.MyTreeUtil;
import com.cmc6.common.util.UserUtil;
import com.cmc6.menu.exception.BizCodeEnum;
import com.cmc6.menu.model.dto.MenuInsertOrUpdateDTO;
import com.cmc6.menu.model.dto.MenuPageDTO;
import com.cmc6.menu.model.vo.MenuInfoByIdVO;
import com.cmc6.menu.service.MenuService;
import com.cmc6.role.service.RoleRefMenuService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, MenuDO> implements MenuService {

    @Resource
    RoleRefMenuService roleRefMenuService;

    /**
     * 新增/修改菜单
     */
    @Override
    @Transactional
    public String insertOrUpdate(MenuInsertOrUpdateDTO dto) {

        if (dto.getId() != null && dto.getId().equals(dto.getParentId())) {
            ApiResult.error(BaseBizCodeEnum.PARENT_ID_CANNOT_BE_EQUAL_TO_ID);
        }

        if (dto.isAuthFlag() && StrUtil.isBlank(dto.getAuths())) {
            ApiResult.error("操作失败：权限菜单的权限不能为空");
        }

        // path不能重复
        if (!dto.isAuthFlag() && StrUtil.isNotBlank(dto.getPath())) {
            Long count = lambdaQuery().eq(MenuDO::getPath, dto.getPath())
                .ne(dto.getId() != null, BaseEntityTwo::getId, dto.getId()).count();
            if (count != 0) {
                ApiResult.error(BizCodeEnum.MENU_URI_IS_EXIST);
            }
        }

        // 如果是起始页面，则取消之前的起始页面
        if (dto.isFirstFlag() && !dto.isAuthFlag()) {
            lambdaUpdate().set(MenuDO::getFirstFlag, false).eq(MenuDO::getFirstFlag, true)
                .ne(dto.getId() != null, BaseEntityTwo::getId, dto.getId()).update();
        }

        // 如果是外链，则清空 一些属性
        if (dto.isLinkFlag()) {
            dto.setRouter(null);
            dto.setRedirect(null);
        }

        if (dto.getId() != null) {
            deleteByIdSetSub(Collections.singleton(dto.getId())); // 先删除 子表数据
        }

        MenuDO entity = getEntityByDTO(dto);
        saveOrUpdate(entity);

        insertOrUpdateSub(entity.getId(), dto); // 新增 子表数据

        return BaseBizCodeEnum.API_RESULT_OK.getMsg();
    }

    /**
     * 新增/修改菜单：新增 子表数据
     */
    private void insertOrUpdateSub(Long id, MenuInsertOrUpdateDTO dto) {

        // 新增：菜单角色 关联表数据
        if (CollUtil.isNotEmpty(dto.getRoleIdSet())) {
            List<RoleRefMenuDO> insertList = new ArrayList<>();
            for (Long item : dto.getRoleIdSet()) {
                RoleRefMenuDO entity = new RoleRefMenuDO();
                entity.setRoleId(item);
                entity.setMenuId(id);
                insertList.add(entity);
            }
            roleRefMenuService.saveBatch(insertList);
        }

    }

    /**
     * 通过 dto，获取 实体类
     */
    private MenuDO getEntityByDTO(MenuInsertOrUpdateDTO dto) {

        MenuDO menuDO = new MenuDO();

        menuDO.setName(dto.getName());
        menuDO.setPath(MyEntityUtil.getNotNullStr(dto.getPath()));
        menuDO.setIcon(MyEntityUtil.getNotNullStr(dto.getIcon()));
        menuDO.setParentId(MyEntityUtil.getNullParentId(dto.getParentId()));
        menuDO.setId(dto.getId());
        menuDO.setOrderNo(dto.getOrderNo());
        menuDO.setEnableFlag(dto.isEnableFlag());
        menuDO.setLinkFlag(dto.isLinkFlag());
        menuDO.setRouter(MyEntityUtil.getNotNullStr(dto.getRouter()));
        menuDO.setRedirect(MyEntityUtil.getNotNullStr(dto.getRedirect()));
        menuDO.setRemark(MyEntityUtil.getNotNullStr(dto.getRemark()));
        menuDO.setFirstFlag(dto.isFirstFlag());
        if (dto.getId() == null) {
            menuDO.setAuthFlag(dto.isAuthFlag()); // 当新增时，才允许设置 authFlag的值
        }
        if (dto.isAuthFlag()) {
            menuDO.setAuths(dto.getAuths()); // 只有权限菜单，才可以设置 auths
            menuDO.setShowFlag(false);
        } else {
            menuDO.setAuths("");
            menuDO.setShowFlag(dto.isShowFlag());
        }

        return menuDO;
    }

    /**
     * 分页排序查询：菜单
     */
    @Override
    public Page<MenuDO> myPage(MenuPageDTO dto) {
        return myPageRes(dto);
    }

    /**
     * 分页排序查询：菜单-返回值
     */
    private Page<MenuDO> myPageRes(MenuPageDTO dto) {

        return lambdaQuery().like(StrUtil.isNotBlank(dto.getName()), MenuDO::getName, dto.getName())
            .like(StrUtil.isNotBlank(dto.getPath()), MenuDO::getPath, dto.getPath())
            .like(StrUtil.isNotBlank(dto.getAuths()), MenuDO::getAuths, dto.getAuths())
            .like(StrUtil.isNotBlank(dto.getRedirect()), MenuDO::getRedirect, dto.getRedirect())
            .eq(dto.getId() != null, BaseEntityTwo::getId, dto.getId())
            .eq(StrUtil.isNotBlank(dto.getRouter()), MenuDO::getRouter, dto.getRouter())
            .eq(dto.getParentId() != null, MenuDO::getParentId, dto.getParentId())
            .eq(dto.getEnableFlag() != null, BaseEntityThree::getEnableFlag, dto.getEnableFlag())
            .eq(dto.getLinkFlag() != null, MenuDO::getLinkFlag, dto.getLinkFlag())
            .eq(dto.getFirstFlag() != null, MenuDO::getFirstFlag, dto.getFirstFlag())
            .eq(dto.getAuthFlag() != null, MenuDO::getAuthFlag, dto.getAuthFlag())
            .eq(dto.getShowFlag() != null, MenuDO::getShowFlag, dto.getShowFlag()).page(dto.getPage());

    }

    /**
     * 查询菜单（树结构）
     */
    @Override
    public List<MenuDO> tree(MenuPageDTO dto) {

        List<MenuDO> resList = new ArrayList<>(); // 本接口返回值

        // 根据条件进行筛选，得到符合条件的数据，然后再逆向生成整棵树，并返回这个树结构
        dto.setPageSize(-1); // 不分页
        List<MenuDO> dbList = myPageRes(dto).getRecords();

        if (dbList.size() == 0) {
            return resList;
        }

        // 查询出所有的菜单
        List<MenuDO> allList = list();

        if (allList.size() == 0) {
            return resList;
        }

        return MyTreeUtil.getFullTreeByDeepNode(dbList, allList);
    }

    /**
     * 删除菜单
     */
    @Override
    @Transactional
    public String deleteByIdSet(NotEmptyIdSet notEmptyIdSet) {

        // 如果存在下级，则无法删除
        Long selectCount = lambdaQuery().in(MenuDO::getParentId, notEmptyIdSet.getIdSet()).count();
        if (selectCount != 0) {
            ApiResult.error(BaseBizCodeEnum.PLEASE_DELETE_THE_CHILD_NODE_FIRST);
        }

        // 删除子表数据
        deleteByIdSetSub(notEmptyIdSet.getIdSet());

        removeByIds(notEmptyIdSet.getIdSet());

        return BaseBizCodeEnum.API_RESULT_OK.getMsg();
    }

    /**
     * 删除子表数据
     */
    private void deleteByIdSetSub(Set<Long> idSet) {

        // 删除 角色菜单关联表
        roleRefMenuService.lambdaUpdate().in(RoleRefMenuDO::getMenuId, idSet).remove();

    }

    /**
     * 获取当前用户绑定的菜单
     */
    @Override
    public List<MenuDO> userMenuList() {
        Long userId = UserUtil.getCurrentUserId();

        if (BaseConstant.ADMIN_ID.equals(userId)) {
            // 如果是 admin账号，则查询所有，条件：不是被禁用了的
            /** 这里和{@link UserUtil#getMenuListByUserId}需要进行同步修改 */
            return lambdaQuery()
                .select(BaseEntityTwo::getId, BaseEntityFour::getParentId, MenuDO::getPath, MenuDO::getIcon,
                    MenuDO::getRouter, MenuDO::getName, MenuDO::getFirstFlag, MenuDO::getLinkFlag, MenuDO::getShowFlag,
                    MenuDO::getAuthFlag).eq(BaseEntityThree::getEnableFlag, 1).orderByDesc(MenuDO::getOrderNo)
                .orderByDesc(BaseEntityTwo::getUpdateTime).list();
        }

        // 获取当前用户绑定的菜单
        return UserUtil.getMenuListByUserId(userId, 1);
    }

    /**
     * 通过主键id，查看详情
     */
    @Override
    public MenuInfoByIdVO infoById(NotNullId notNullId) {

        MenuInfoByIdVO resVO = BeanUtil.copyProperties(getById(notNullId.getId()), MenuInfoByIdVO.class); // 本方法 返回值

        // 设置 角色 idSet
        List<RoleRefMenuDO> roleRefMenuList =
            roleRefMenuService.lambdaQuery().eq(RoleRefMenuDO::getMenuId, notNullId.getId())
                .select(RoleRefMenuDO::getRoleId).list();
        resVO.setRoleIdSet(roleRefMenuList.stream().map(RoleRefMenuDO::getRoleId).collect(Collectors.toSet()));

        return resVO;
    }

    /**
     * 通过主键 idSet，加减排序号
     */
    @Override
    @Transactional
    public String addOrderNo(AddOrderNoDTO dto) {

        if (dto.getNumber() == 0) {
            return BaseBizCodeEnum.API_RESULT_OK.getMsg();
        }

        List<MenuDO> listByIds = listByIds(dto.getIdSet());

        for (MenuDO item : listByIds) {
            item.setOrderNo(item.getOrderNo() + dto.getNumber());
        }

        updateBatchById(listByIds);

        return BaseBizCodeEnum.API_RESULT_OK.getMsg();
    }
}




